package com.example.seckill.mq;

import com.example.seckill.common.RedisKey;
import com.example.seckill.dao.SeckillGoodsMapper;
import com.example.seckill.dao.SeckillOrderMapper;
import com.example.seckill.entity.SeckillOrder;
import com.example.seckill.entity.OrderStatus;
import com.example.seckill.entity.SeckillGoods;
import com.example.seckill.service.SeckillService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import java.io.IOException;
import org.springframework.transaction.annotation.Transactional;

@Component
@Slf4j
public class SeckillMessageReceiver {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    
    @Autowired
    private SeckillOrderMapper seckillOrderMapper;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private SeckillService seckillService;

    @Transactional(rollbackFor = Exception.class)
    protected boolean doCreateOrder(Long userId, Long goodsId, String orderKey) {
        // 创建订单
        SeckillOrder order = new SeckillOrder();
        order.setUserId(userId);
        order.setGoodsId(goodsId);
        order.setOrderStatus(OrderStatus.UNPAID.getCode());
        
        // 保存订单并更新库存
        if (seckillOrderMapper.insert(order) > 0 && seckillGoodsMapper.reduceStock(goodsId) > 0) {
            // 设置用户订单状态
            redisTemplate.opsForValue().set(orderKey, order.getId());
            log.info("秒杀成功 - userId: {}, goodsId: {}, orderId: {}", userId, goodsId, order.getId());
            return true;
        }

        // 检查失败原因
        SeckillGoods goods = seckillGoodsMapper.selectById(goodsId);
        
        // 1. 商品不存在，确认消息，不再重试
        if (goods == null) {
            log.error("商品不存在 - goodsId: {}", goodsId);
            return true;  // 返回true让上层确认消息
        }
        
        // 2. 库存不足，确认消息，不再重试
        if (goods.getStock() <= 0) {
            log.warn("数据库库存不足 - goodsId: {}", goodsId);
            // 同步Redis库存
            String stockKey = RedisKey.SECKILL_STOCK_PREFIX + goodsId;
            redisTemplate.opsForValue().set(stockKey, 0);
            return true;  // 返回true让上层确认消息
        }
        
        // 3. 其他原因（如并发冲突），返回false重试
        log.warn("创建订单失败（将重试） - userId: {}, goodsId: {}", userId, goodsId);
        return false;
    }

    private void createOrder(SeckillMessage message, Channel channel, long tag) throws IOException {
        Long userId = message.getUserId();
        Long goodsId = message.getGoodsId();
        
        try {
            // 检查是否重复下单
            String orderKey = RedisKey.SECKILL_ORDER_PREFIX + userId + ":" + goodsId;
            if (Boolean.TRUE.equals(redisTemplate.hasKey(orderKey))) {
                channel.basicAck(tag, false);
                return;
            }

            // 获取商品库存
            int stock = seckillService.getStockFromCache(goodsId);
            if (stock <= 0) {
                log.warn("商品库存不足 - goodsId: {}", goodsId);
                channel.basicAck(tag, false);
                return;
            }

            // 创建订单（事务处理）
            if (doCreateOrder(userId, goodsId, orderKey)) {
                channel.basicAck(tag, false);
            } else {
                log.warn("创建订单失败 - userId: {}, goodsId: {}", userId, goodsId);
                channel.basicNack(tag, false, true);  // 业务失败时重试
            }
        } catch (Exception e) {
            log.error("处理订单异常", e);
            try {
                channel.basicNack(tag, false, true);  // 系统异常时也重试
            } catch (Exception ex) {
                log.error("消息重试失败", ex);
            }
        }
    }

    @RabbitListener(queues = "seckill.queue", ackMode = "MANUAL")
    public void receive(SeckillMessage message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        if (message == null || message.getUserId() == null || message.getGoodsId() == null) {
            channel.basicAck(tag, false);
            return;
        }
        createOrder(message, channel, tag);
    }
} 